package com.btm.planb.diffobject.generate.code;

import com.btm.planb.diffobject.generate.info.ClassInfo;
import com.btm.planb.diffobject.generate.info.MethodInfo;
import com.btm.planb.diffobject.generate.util.StringUtils;

import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * code模板
 */
public final class CodeTemplate {

    private CodeTemplate() {}

    /**
     * java class类框架主体，<br/>
     * 主要为package、import、class name以及备注信息
     * @param classInfo class类主体信息
     * @return
     */
    public static String printClass(ClassInfo classInfo) {
        String template = "package {0};\n\n" +
                "{1}\n" +
                "//Auto generated by diff-object-generate, do not modify!!\n\n" +
                "{2}";
        return MessageFormat.format(template, classInfo.getPackageName(), classInfo.printImport(), printClassDeclare(classInfo));
    }

    /**
     * java class文件主体定义,<br/>
     * 主要为类名称及实现的接口名称
     * @param classInfo  class类主体信息
     * @return
     */
    public static String printClassDeclare(ClassInfo classInfo) {
        String template = "public class {0} implements {1} '{'\n" +
                "{2}\n" +
                "'}'\n";
        return MessageFormat.format(template, classInfo.className(), classInfo.getInterfaceName(), classInfo.printMethods());
    }

    /**
     * java 方法主体定义，<br/>
     * 主要为方法返回值类型、方法名称、方法参数列表以及方法体
     * @param methodInfo 方法信息
     * @param body 方法体
     * @return
     */
    public static String printMethod(MethodInfo methodInfo, String body) {
        String template = "public {0} {1} ({2}) '{'\n" +
                "{3}" +
                "'}'\n";
        return MessageFormat.format(template, methodInfo.getReturnTypeElement().getSimpleName().toString(),
                methodInfo.getMethodName(), methodParameters(methodInfo), body);
    }

    /**
     * 判空逻辑
     * @param templateObject 模版对象
     * @param targetName 目标对象名称
     * @param targetFileName 目标字段名称
     * @param sourceName 数据来源对象名称
     * @param sourceFileName 数据来源字段名称
     * @return
     */
    public static String printIfNullCodeFragment(String templateObject, String targetName, String targetFileName, String sourceName, String sourceFileName) {
        String template = "if(Objects.nonNull({0}.get{1}())) '{'\n" +
                printSetterGetter(targetName, targetFileName, sourceName, sourceFileName) +
                "'}' else '{'\n" +
                printSetterGetter(targetName, targetFileName, templateObject, targetFileName) +
                "'}'\n";
        return MessageFormat.format(template, sourceName, StringUtils.convertInitialUpper(sourceFileName));
    }

    /**
     * 从数据源对象的getter方法取值并传入目标对象的setter方法
     * @param targetName 目标对象名称
     * @param targetFileName 目标字段名称
     * @param sourceName 数据源对象名称
     * @param sourceFileName 数据源字段名称
     * @return
     */
    public static String printSetterGetter(String targetName, String targetFileName, String sourceName, String sourceFileName) {
        String template = "{0}.set{1}({2}.get{3}());\n";
        return MessageFormat.format(template, targetName, StringUtils.convertInitialUpper(targetFileName),
                sourceName, StringUtils.convertInitialUpper(sourceFileName));
    }

    /**
     * new对象
     * @param returnType 返回值的类型
     * @param returnObjectName 返回值对象的名称
     * @return
     */
    public static String printNewObject(String returnType, String returnObjectName) {
        String template = "{0} {1} = new {0}();\n";
        return MessageFormat.format(template, returnType, returnObjectName);
    }

    /**
     * 方法返回语句
     * @param returnObjectName 返回值对象的名称
     * @return
     */
    public static String printReturn(String returnObjectName) {
        String template = "return {0};\n";
        return MessageFormat.format(template, returnObjectName);
    }

    /**
     * 组装方法签名
     * @param methodInfo 方法信息
     * @return 方法签名
     */
    private static String methodParameters(MethodInfo methodInfo) {
        if (Objects.isNull(methodInfo.getParameterInfos()) || methodInfo.getParameterInfos().isEmpty()) {
            return "";
        }
        List<String> parameterStr = methodInfo.getParameterInfos().stream().map(item ->
                item.getName() + " " + item.getVariableName()).collect(Collectors.toList());
        return String.join(",", parameterStr);
    }

}
